import java.io.BufferedReader;
import java.io.FileReader;

/**
 * This class holds the attributes that all characters in the game share
 * @author Darrien Richmond
 * 
 */
public abstract class Character extends Collidable{
	public enum Speeds{STOP,MOVEMENT,DASH};
	Collidable wall;
	private float badDirection = 90000;
	Sprite standSprite;
	Sprite deadSprite;
	Sprite guardSprite;
	Sprite chargeSprite;
	Sprite forwardSprite;
	Sprite backwardSprite;
	Sprite ultSequenceSprite;
	Sprite blastSprite;
	Sprite energyBlastSprite;
	Sprite hitBodySprite;
	Sprite hitFaceSprite;
	Sprite hitUpSprite;
	Sprite knockBackSprite;
	Sprite specialAbilitySprite;
	Sprite transformSprite;
	Sprite currentSprite;
	Sprite energyAttack0Sprite;
	Sprite energyAttack1Sprite;
	Sprite energyBlastAttackSprite;
	float currentLp;
	float currentEp;
	float currentRp;
	float lpRegin;
	float rpRegin;
	float epRegin;
	float lpMax;
	float rpMax;
	float epMax;
	float attackDamage;
	float energyDamage;
	float blockReduction;
	float engBlockDrain;
	float movementSpeed;
	int specialType; //0 is transformation (Kaioken), 1 is passive, 2 is buff, 3 is attack 
	int ultStyle; //0 is an energy attack, 1 is a collision cutscene, 2 is a stat boost
	int killCount;
	int deathCount;
	int characterNumber;
	float eAttackSpeed;
	float mAttackSpeed;
	boolean loaded;
	boolean released;
	public boolean moved = true;
	EnergyAttack wave;
	MovementPacket currentMovementPacket;
	Point prev0;
	Point prev1;
	Point prev2;
	String path;  //file path to decode#.txt
	public static final float LP_REGIN = 1;
	public static final float EP_REGIN = 1;
	public static final float RP_REGIN = 1;
	public static final float ATTACK_DAMAGE = 10;
	public static final float ENG_DAMAGE = 10;
	public static final float BLOCK_REDUCTION = .3f;
	public static final float ENG_BLOCK_DRAIN = 10;
	public static final float SPEED = 5;
	public static final float M_ATTACK_SPEED = 5;
	public static final float E_ATTACK_SPEED = 5;
	
	
	/**
	 * this constructor sets 3 starting values for the character, and
	 * sets everything else to a default value
	 * @param lpMax the max lp of the character
	 * @param epMax the max ep of the character
	 * @param rpMax the max rp of the character
	 */
	public Character()
	{
		super();
		this.lpMax = 100;
		this.rpMax = 100;
		this.epMax = 100;
		this.lpRegin = LP_REGIN;
		this.epRegin = EP_REGIN;
		this.rpRegin = RP_REGIN;
		this.mAttackSpeed = M_ATTACK_SPEED;
		this.eAttackSpeed = E_ATTACK_SPEED;
		this.attackDamage = ATTACK_DAMAGE;
		this.energyDamage = ENG_DAMAGE;
		this.blockReduction = BLOCK_REDUCTION;
		this.engBlockDrain = ENG_BLOCK_DRAIN;
		this.movementSpeed = 10;
		this.killCount = 0;
		this.deathCount = 0;
		this.currentPosition = new Point(1500, 1000);
		prev0 = new Point(0,0);
		prev1 = new Point(0,0);
		prev2 = new Point(0,0);
		released = true;
		radius = 50;
		path = getClass().getClassLoader().getResource(".").getPath()+ "DecodeImage";
		currentMovementPacket = new MovementPacket(true,0,Speeds.STOP);
	}
	/**
	 * sets all of the sprite variables based on the information from the
	 * text document DecodeImage
	 */
	public void loadSprites()
	{
		FileReader fr;
		String num = characterNumber + "";
		if(num.length() == 1)
		{
			num = "0" + num;
		}
		System.out.println(num);
		try {
			fr = new FileReader(path + num + ".txt");

		BufferedReader br = new BufferedReader(fr);
		String str = br.readLine();
		int[] ans = decode(str);
		standSprite = new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		deadSprite = new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		guardSprite = new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		chargeSprite= new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		forwardSprite= new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		backwardSprite= new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		ultSequenceSprite= new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		blastSprite= new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		energyBlastSprite= new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		hitBodySprite= new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		hitFaceSprite= new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		hitUpSprite= new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		knockBackSprite= new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		energyAttack0Sprite= new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		energyBlastAttackSprite = new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		str = br.readLine();
		ans = decode(str);
		specialAbilitySprite= new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
//		str = br.readLine();
//		ans = decode(str);
//		transformSprite= new Sprite(0,ans[0],new Key(characterNumber,ans[1],ans[2],ans[3]));
		currentSprite= standSprite;
		br.close();
		fr.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		loaded = true;
	}
	private int[] decode(String str)
	{
		str = str.replace(" ", "");
		int speed = Integer.parseInt("" + str.charAt(0) + str.charAt(1));
		int type = Integer.parseInt(str.charAt(2) + "");
		int start = Integer.parseInt(str.charAt(3) + "");
		int end = Integer.parseInt(str.charAt(4) + "");
		int[] ans = {speed,type,start,end};
		return ans;
		
	}
	/**
	 * gets the current sprite being used by the character
	 * @return currentSprite
	 */
	public Sprite getCurrentSprite()
	{
		return currentSprite;
	}
	/**
	 * gets the current position of the player
	 * @return currentPosition
	 */
	public Point getPosition()
	{
		return currentPosition;
	}
	public EnergyAttack getEnergyAttack()
	{
		if(wave != null)
		{
			if(wave.isAlive() == true)
			{
				return wave;
			}
		}
		return null;
	}
	/**
	 * tells the character to move in its currentMovementPacket.getDirection() based on its current speed
	 */
	public void move()
	{
		prev0.setX(prev1.getX());
		prev0.setY(prev1.getY());
		prev1.setX(prev2.getX());
		prev1.setY(prev2.getY());
		prev2.setX(getCurrentPosition().getX());
		prev2.setY(getCurrentPosition().getY());
		if(released == true )
		{
			float speed = 0;
			if(currentMovementPacket != null)
			{
				speed = getSpeed(currentMovementPacket.getSpeed());
				if(speed >0)
				{
					moved = true;
				}
				if(currentMovementPacket.getDirection() != badDirection)
				{
					currentPosition.setX((float)(currentPosition.getX() + Math.cos(currentMovementPacket.getDirection())*speed));
					currentPosition.setY((float)(currentPosition.getY() + Math.sin(currentMovementPacket.getDirection())*speed));
					badDirection = 90000;
				}
			}
			if(moved == true)
			{
				if(speed == 0)
				{
					setSprite(standSprite);
				}
				else
				{
					setSprite(forwardSprite);
				}
			}
		}
		//if you hit a wall, don't move
		if(wall != null)
		{
			badDirection = currentMovementPacket.getDirection();
			wall = null;
			currentPosition.setX(prev0.getX());
			currentPosition.setY(prev0.getY());
		}
		if(currentSprite != null)
		{
			currentSprite.update();
		}
	}
	public void sendMovementPacket(MovementPacket packet)
	{
		if(currentMovementPacket != null)
		{
			if(currentMovementPacket.getWill() == true)
			{
				currentMovementPacket = packet;
			}
		}
		else
		{
			currentMovementPacket = packet;
		}
	}
	/**
	 * sets the speed of the character
	 * @param s the preset speed the character should be set to
	 */
	private float getSpeed(Speeds s)
	{
		if(s == Speeds.MOVEMENT)
		{
			return movementSpeed;
		}
		else if(s == Speeds.DASH)
		{
			return movementSpeed *1.3f;
		}
		else
		{
			return 0f;
		}
	}
	/**
	 * gets the current direction of the player
	 * @return current direction
	 */
	public float getDirection()
	{
		return currentMovementPacket.getDirection();
	}

	/**
	 * inflicts a set amount of damage on the character
	 * @param dmg the amount of damage
	 */
	public void damage(float dmg)
	{
		currentLp = currentLp - dmg;
	}
	/**
	 * sets the current sprite to the input sprite, and changes the angle
	 * to be the player's current direction
	 * @param sprite sprite to change the current sprite to
	 */
	public void setSprite(Sprite sprite)
	{
		if(characterSet() == true)
		{
			currentSprite = sprite;
			sprite.setAngle(getDirection());
		}
	}
	public void setCharacterNumber(int i)
	{
		this.characterNumber = i;
		loadSprites();
	}
	public int getCharacterNumber()
	{
		return characterNumber;
	}
	public boolean characterSet()
	{
		return loaded;
	}
	
}
